package com.coder.rental.security;

import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;

/**
 * spring security配置类（springboot3）
 * 不同于springboot2（要继承WebSecurity）
 */
@Configuration // 声明配置
@EnableWebSecurity
public class SecurityConfig {

    // 注入（都有Component注解，都可以被spring容器管理）
    @Resource
    private LoginSuccessHandler loginSuccessHandler; // 访问成功
    @Resource
    private LoginFailHandler loginFailHandler; // 访问失败
    @Resource
    private CustomerAccessDeniedHandler customerAccessDeniedHandler; // 访问拒绝
    @Resource
    private CustomAnonymousEntryPoint customAnonymousEntryPoint; // 匿名用户无权访问
    @Resource
    private CustomerUserDetailsService customerUserDetailsService;

    // 配置安全过滤链
    // 1 用户通过表单提交 username 和 password。
    // 2 SecurityFilterChain 会通过 formLogin() 来处理登录请求。
    // 3 Spring Security 会通过配置的 UserDetailsService（即 CustomerUserDetailsService）加载用户信息。
    // 4 loadUserByUsername 查询数据库并返回用户信息，如果用户存在，则返回用户对象。
    // 5 然后，Spring Security 会调用 PasswordEncoder 实现类（即 CustomerPasswordEncoder）的 matches 方法来校验密码：
    // 6 matches(rawPassword, encodedPassword)：它会将输入的明文密码（rawPassword）加密后与数据库存储的加密密码（encodedPassword）进行比较。
    // 7 如果密码匹配，认证成功，用户登录；否则，登录失败
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{ // throw new 用于在方法内部显式抛出异常。throws 用于在方法签名中声明该方法可能抛出的异常。
        // 整合处理器：
        // 1 登录前过滤
        // todo（token）
        // 2 登录过程处理
        // 表单登录（formLogin）是通过 POST 请求 来提交用户名和密码的（默认使用参数就是username和password）
        // http://localhost:8888/rental/user/login?username=common_admin&password=111111
        http.formLogin()
                .loginProcessingUrl("/rental/user/login") // 设置登录处理URL
                .successHandler(loginSuccessHandler) // 设置登录成功处理器
                .failureHandler(loginFailHandler) // 设置登录失败处理器
                .and()
                // 对session会话管理
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 设置会话创建策略为无状态
                .and()
                // 授权
                .authorizeHttpRequests() // 授权请求配置
                .requestMatchers("/rental/user/login") // 匹配登录请求
                .permitAll() // 允许所有请求访问
                .anyRequest().authenticated() // 任何其他请求需要认证
                .and()
                // 异常处理配置
                .exceptionHandling()
                .authenticationEntryPoint(customAnonymousEntryPoint) // 匿名访问
                .accessDeniedHandler(customerAccessDeniedHandler) // 访问拒绝
                .and()
                // 跨域配置
                .cors()
                .and()
                // 关闭CSRF保护（跨站请求伪造，是一种网络攻击）
                .csrf().disable()
                .userDetailsService(customerUserDetailsService); // 设置用户详情服务
        return http.build(); // 构建并返回安全过滤链
    }

}
